/*
 * gpio.c
 *
 *  Created on: Aug 18, 2012
 *      Author: drew
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "gpio.h"

/*
 * Private Methods
 */

int iGPIOStringLength( char * cString )
{
  int iCount = 0;

  /* Look for end of string delimiter */
  while( *(cString++) != '\0' )
  {
    iCount++;
  }

  return iCount;
}

/*
 * Public Methods
 */

xpGPIODescription xpGPIOCreateObject( int iPort, int iPin, eGPIODirection eDirection)
{
  xpGPIODescription xpGPIOObject = (xpGPIODescription)malloc( sizeof( xGPIODescription ) );

  xpGPIOObject->iPin = iPin;
  xpGPIOObject->iPort = iPort;
  xpGPIOObject->eDirection = eDirection;
  xpGPIOObject->iSystemPinNumber = ( xpGPIOObject->iPort * 32 ) + xpGPIOObject->iPin;

  return xpGPIOObject;
}

void vGPIODestroyObject( xpGPIODescription xpGPIO )
{
  free( xpGPIO );
}

int iGPIOInitialize( xpGPIODescription xpGPIO )
{
  FILE * fpGPIO = NULL;
  char cFileBuff[64], cFileName[64];


  /*
   * Export pin
   */

  /* Open export file with Append Binary */
  if( ( fpGPIO = fopen( "/sys/class/gpio/export", "ab" ) ) == NULL )
  {
    printf( "ERROR: Cannot export GPIO - Port: %d, Pin: %d\n", xpGPIO->iPort, xpGPIO->iPin );
    return 1;
  }

  /* Assign correct pin size */
  sprintf( cFileBuff, "%d",  xpGPIO->iSystemPinNumber );

  /* Write to export file to export pin */
  fwrite( cFileBuff, sizeof( char ), iGPIOStringLength( cFileBuff ), fpGPIO );

  /* Close export file, it is no longer needed */
  fclose( fpGPIO );

  /*
   * Set GPIO Direction
   */

  /* Format file name */
  sprintf( cFileName, "/sys/class/gpio/gpio%d/direction", xpGPIO->iSystemPinNumber );

  /* Open file with Read/Write Binary */
  if( ( fpGPIO = fopen( cFileName, "rb+") ) == NULL )
  {
    printf( "ERROR: Cannot open GPIO Direction - Port: %d, Pin: %d\n", xpGPIO->iPort, xpGPIO->iPin );
    return 1;
  }

  switch( xpGPIO->eDirection )
  {
    case GPIO_IN:
      sprintf( cFileBuff, "in" );
      break;
    case GPIO_OUT:
      sprintf( cFileBuff, "out" );
      break;
    default:
      break;
  }

  fwrite( cFileBuff, sizeof( char ), iGPIOStringLength( cFileBuff ), fpGPIO );

  fclose( fpGPIO );

  return 0;

}

int iGPIOCleanup( xpGPIODescription xpGPIO )
{
  FILE * fpGPIO = NULL;
  char cFileBuff[64];

  /* Open unexport file with Append Binary */
  if( ( fpGPIO = fopen( "/sys/class/gpio/unexport", "ab" ) ) == NULL )
  {
    printf( "ERROR: Cannot unexport GPIO - Port: %d, Pin: %d\n", xpGPIO->iPort, xpGPIO->iPin );
    return 1;
  }

  sprintf( cFileBuff, "%d", xpGPIO->iSystemPinNumber );

  fwrite( cFileBuff, sizeof( char ), iGPIOStringLength( cFileBuff ), fpGPIO );

  fclose( fpGPIO );

  return 0;
}

int iGPIOSetOutput( xpGPIODescription xpGPIO )
{
  FILE * fpGPIO = NULL;
  char cFileBuff[64], cFileName[64];

  sprintf( cFileName, "/sys/class/gpio/gpio%d/value", xpGPIO->iSystemPinNumber );

  /* Open file with Read/Write Binary */
  if( ( fpGPIO = fopen( cFileName, "rb+" ) ) == NULL )
  {
    printf( "ERROR: Cannot set GPIO - Port: %d, Pin: %d\n", xpGPIO->iPort, xpGPIO->iPin );
    return 1;
  }

  sprintf( cFileBuff, "1" );

  fwrite( cFileBuff, sizeof( char ), iGPIOStringLength( cFileBuff ), fpGPIO );

  fclose( fpGPIO );

  return 0;
}

int iGPIOClearOutput( xpGPIODescription xpGPIO )
{
  FILE * fpGPIO = NULL;
  char cFileBuff[64], cFileName[64];

  sprintf( cFileName, "/sys/class/gpio/gpio%d/value", xpGPIO->iSystemPinNumber );

  /* Open file with Read/Write Binary */
  if( ( fpGPIO = fopen( cFileName, "rb+" ) ) == NULL )
  {
    printf( "ERROR: Cannot set GPIO - Port: %d, Pin: %d\n", xpGPIO->iPort, xpGPIO->iPin );
    return 1;
  }

  sprintf( cFileBuff, "0" );

  fwrite( cFileBuff, sizeof( char ), iGPIOStringLength( cFileBuff ), fpGPIO );

  fclose( fpGPIO );

  return 0;
}

int iGPIOReadInput( xpGPIODescription xpGPIO )
{
  FILE * fpGPIO = NULL;
  char cFileBuff[64], cFileName[64];

  sprintf( cFileName, "/sys/class/gpio/gpio%d/value", xpGPIO->iSystemPinNumber );

  /* Open file with Read/Write Binary */
  if( ( fpGPIO = fopen( cFileName, "rb+" ) ) == NULL )
  {
    printf( "ERROR: Cannot set GPIO - Port: %d, Pin: %d\n", xpGPIO->iPort, xpGPIO->iPin );
    return 1;
  }

  sprintf( cFileBuff, "0" );

  fread( cFileBuff, sizeof( char ), 1, fpGPIO );

  fclose( fpGPIO );

  return 0;
}
